#ifndef RETINAFACE_DET_H
#define RETINAFACE_DET_H

#include <iostream>
#include <string>
#include <opencv2/opencv.hpp>
#include <unistd.h>
#include <omp.h>
#include<mutex>
#include "rt_model_operation.h"

using namespace algocommon;



namespace retinaface
{
    struct InitParams: public OnnxModeltoTRTParam
    {
        int gpu_id;
        std::string onnx_model_path;
        std::string trt_model_dir;
        std::string trt_model_name;
        float thresh = 0.7;
    };

    struct Anchor
    {
        float x;
        float y;
        float w;
        float h;
        float score;
        std::vector<cv::Point2f> landmarks;
    };


    class RetinaFace: public OnnxModeltoTRT
    {
    public:

        RetinaFace(const InitParams &params);

        virtual  ~RetinaFace();
    

    public:
        void Execute(const cv::Mat &org_img, std::vector<cv::Rect> &rectangles, std::vector<float> &confidence,
                            std::vector<std::vector<cv::Point>> &landmarks);
        void Execute(const std::vector<cv::Mat>&org_img, 
                                    std::vector<std::vector<cv::Rect>>&rectangles, 
                                    std::vector<std::vector<float>>&confidence,
                                    std::vector<std::vector<std::vector<cv::Point>>>&landmarks);

    private:

        Result InitNetwork();

        void PreProcessGpu(const cv::Mat &input);
        void PreProcessGpu(const std::vector<cv::Mat> &imgs);

        bool CheckAndRefineBox(float &xmin, float &ymin, float &xmax, float &ymax);
        void PostProcessGpu(std::vector<TensorFloat> &outputs,
                                                        std::vector<cv::Rect> &rectangles,
                                                        std::vector<float> &confidence,
                                                        std::vector<std::vector<cv::Point>> &landmarks);
                                                        
         void PostProcessGpu(std::vector<TensorFloat> &outputs,
                                                        std::vector<std::vector<cv::Rect>> &rectangles,
                                                        std::vector<std::vector<float>>&confidence,
                                                        std::vector<std::vector<std::vector<cv::Point>>> &landmarks);       

        void PriorBox(int width, int height);
    private:

        TensorUint8 sized_input_; // 图片和输入一样大 也是最终网络输入
        TensorUint8 origin_input_; // origin_input_ 贴入网络 sized_input_
        TensorUint8 mat_input_;   //图片大于输入  需要宽高 同比例 resize到 origin_input_
        TensorFloat anchors_;
        TensorFloat box_tensor_;
        TensorFloat key_score_in_;
        TensorInt32 value_index_in_;
        TensorFloat key_score_out_;
        TensorInt32 value_index_out_;
        TensorUint8 sort_buffer_;
        TensorInt32 offset_buffer_;
        TensorFloat sorted_box_tensor_;
        TensorFloat nms_box_tensor_;


    private:

        InitParams params_;

        std::mutex mutex_;
        float image_scale_ = 1.0f;
        std::vector<float> image_scales_;

        std::vector<float> mean_vec_ = {-104.0f, -117.0f, -123.0f};
        std::vector<float> alphas_ = {1.f, 1.f, 1.f};
        float nms_thresh_ = 0.4;
        std::vector<std::vector<int>> min_sizes_ = {{16, 32}, {64, 128}, {256, 512}}; //anchor size
        std::vector<int> steps_ = {8, 16, 32};
        unsigned int sorted_topk_ = 800;
        int nms_topk_ = 500;


    };



};//namespace retinaface

#endif